import asyncio
import uvicorn
import os
import socket
from py_eureka_client.eureka_client import EurekaClient
from fastapi import FastAPI

class EurekaServiceRegistrar:
    """
    Eureka服务注册器类，用于简化服务注册到Eureka服务器的过程
    现在作为纯工具类，接受外部传入的FastAPI应用实例
    """
    
    def __init__(self, app: FastAPI, app_name: str, port: int, eureka_server_url: str = None):
        """
        初始化Eureka服务注册器
        
        参数:
            app (FastAPI): 外部传入的FastAPI应用实例
            app_name (str): 服务名称，在Eureka注册中心中标识此服务
            port (int): 服务运行的端口号
            eureka_server_url (str): Eureka服务器的地址
        """
        # 接收外部传入的FastAPI应用实例
        self.app = app
        # 保存传入的参数
        self.app_name = app_name
        self.port = port
        # 优先从环境变量获取Eureka服务器地址，如果没有则使用传入的值或默认值
        self.eureka_server_url = eureka_server_url or os.environ.get('EUREKA_SERVER_URL', 'http://eureka-server:8761/eureka/')
        # 初始化客户端为None
        self.client = None
        
        # 根据参数生成实例ID
        self.instance_id = f"{app_name.lower().replace('_', '-')}-{port}"
        
        # 注册健康检查和状态端点
        self._register_endpoints()
        # 设置事件监听器
        self._setup_event_handlers()
    
    def _register_endpoints(self):
        """注册服务所需的端点"""
        
        # 检查是否已存在相同路径的端点
        existing_paths = {route.path for route in self.app.routes}
        
        # 添加健康检查端点，供Eureka调用
        if "/health" not in existing_paths:
            @self.app.get("/health")
            async def health_check():
                return {"status": "UP"}
        
        # 添加状态页面端点
        if "/status" not in existing_paths:
            @self.app.get("/status")
            async def get_status():
                return {"status": "UP"}
        
        # 添加手动注销端点
        if "/deregister" not in existing_paths:
            @self.app.get("/deregister")
            async def deregister_service():
                if self.client:
                    await self.client.stop()
                    print(f"服务{self.app_name}已从Eureka注销！")
                    return {"status": "success", "message": "Service deregistered from Eureka"}
                else:
                    return {"status": "error", "message": "Eureka client not initialized"}
    
    def _setup_event_handlers(self):
        """设置FastAPI应用的事件处理器"""
        
        # 保存原始的startup和shutdown事件处理器
        original_startup_handlers = self.app.router.on_startup.copy()
        original_shutdown_handlers = self.app.router.on_shutdown.copy()
        
        # 清空现有的事件处理器
        self.app.router.on_startup.clear()
        self.app.router.on_shutdown.clear()
        
        # 先添加原始的startup处理器
        for handler in original_startup_handlers:
            self.app.router.add_event_handler("startup", handler)
        
        # 添加Eureka启动处理器
        @self.app.on_event("startup")
        async def _on_startup():
            await self.start_eureka_client()
        
        # 先添加Eureka关闭处理器
        @self.app.on_event("shutdown")
        async def _on_shutdown():
            if self.client:
                await self.client.stop()
                print(f"服务{self.app_name}已在关闭时从Eureka注销！")
        
        # 再添加原始的shutdown处理器
        for handler in original_shutdown_handlers:
            self.app.router.add_event_handler("shutdown", handler)
    
    async def start_eureka_client(self):
        """启动Eureka客户端并注册服务"""
        try:
            # 获取环境变量中的公共访问地址，如果没有则使用容器名或主机名
            public_host = os.environ.get('PUBLIC_HOST', '')
            
            # 如果没有提供公共访问地址，则使用容器名或主机名
            if not public_host:
                instance_host = os.environ.get('HOSTNAME', socket.gethostname())
                # 用于在Eureka中注册的URL
                register_host = instance_host
            else:
                # 使用公共访问地址进行注册
                instance_host = os.environ.get('HOSTNAME', socket.gethostname())
                register_host = public_host
                print(f"使用公共访问地址 {public_host} 进行服务注册")
            
            # 创建Eureka客户端实例
            self.client = EurekaClient(
                eureka_server=self.eureka_server_url,
                app_name=self.app_name,
                instance_host=instance_host,
                instance_ip="",  # 让Eureka自动检测IP
                instance_port=self.port,
                instance_id=self.instance_id,
                home_page_url=f"http://{register_host}:{self.port}",
                status_page_url=f"http://{register_host}:{self.port}/status",
                health_check_url=f"http://{register_host}:{self.port}/health"
            )
            
            # 连接到Eureka服务器并完成服务注册
            print(f"正在尝试连接到Eureka服务器: {self.eureka_server_url}...")
            await self.client.start()
            print(f"服务{self.app_name}已成功注册到Eureka！注册地址: http://{register_host}:{self.port}")
        except Exception as e:
            print(f"注册服务时发生错误: {e}")
    
    def run(self, host="0.0.0.0"):
        """
        运行FastAPI服务
        
        参数:
            host (str): 主机地址，默认为0.0.0.0
        """
        print(f"启动{self.app_name}服务，端口{self.port}...")
        uvicorn.run(self.app, host=host, port=self.port)
    
    async def stop(self):
        """停止Eureka客户端"""
        if self.client:
            await self.client.stop()
            print(f"服务{self.app_name}已从Eureka注销！")

# 提供一个便捷函数，让用户可以直接调用
async def register_eureka_service(app: FastAPI, app_name: str, port: int, eureka_server_url: str = "http://localhost:8761/eureka/"):
    """
    便捷函数，用于快速创建并启动Eureka服务注册
    
    参数:
        app (FastAPI): 外部传入的FastAPI应用实例
        app_name (str): 服务名称
        port (int): 服务端口
        eureka_server_url (str): Eureka服务器地址
    
    返回:
        EurekaServiceRegistrar: 服务注册器实例
    """
    registrar = EurekaServiceRegistrar(app, app_name, port, eureka_server_url)
    await registrar.start_eureka_client()
    return registrar

